#include <syscall.h>
#include <random.h>
#include <string.h>
#include <stdint.h>
#include "tests/filesys/seq-test.h"
#include "tests/lib.h"
#include "tests/main.h"
const unsigned int buf_size = 4*1024+42;
const int num_of_child = 30;
static uint64_t start_cycles = 0;
void test_write(const char* filename);
void shuffle_int (int *buf, size_t cnt);
void swap(int* a, int* b);
static inline uint64_t get_cycles (void);

void swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

void shuffle_int (int *buf, size_t cnt) 
{
  size_t i;

  for (i = 0; i < cnt; i++)
    {
      size_t j = i + random_ulong () % (cnt - i);
      swap (buf + i, buf + j);
    }
}

static inline uint64_t get_cycles (void)
{
	  uint64_t ret = 0;
	  __asm__ __volatile__("rdtsc" : "=A" (ret));
  return ret;
}

void test_write(const char* filename)
{
	char buf[buf_size];
	int write_order[buf_size];
	size_t i;
	int fd;
	size_t written = 0;
	size_t  ofs = 0;
	size_t block_size = 512;

	random_bytes (buf, buf_size);
	msg("test random write");
	CHECK (create (filename, buf_size), "create \"%s\"", filename);
	CHECK ((fd = open (filename)) > 1, "open \"%s\"", filename);

	for(i = 0; i < buf_size; i++)
	{
		write_order[i] = i;
	}

	shuffle_int(write_order, buf_size);

	msg ("writing \"%s\"", filename);
	start_cycles = get_cycles();
	while(written < buf_size)
	{
		seek(fd, write_order[written]);

		if(write(fd, &buf[write_order[written]], 1) != 1)
		{
			fail("write 1 byte in random order failed");
		}

		written ++;
	}
	msg ("close \"%s\"", filename);
	//write to disk if using disk cache
	close(fd);
	msg ("total cycle to write random : %lld", get_cycles()-start_cycles);
	//check is same
	check_file (filename, buf, buf_size);

	remove(filename);

	msg("test sequential write");
	random_bytes (buf, buf_size);
	CHECK (create (filename, buf_size), "create \"%s\"", filename);
	CHECK ((fd = open (filename)) > 1, "open \"%s\"", filename);

	msg ("writing \"%s\"", filename);
	start_cycles = get_cycles();
	while (ofs < buf_size) 
	{
		if (block_size > buf_size - ofs)
			block_size = buf_size - ofs;

		if (write (fd, buf + ofs, block_size) != (int) block_size)
			fail ("write %zu bytes at offset %zu in \"%s\" failed",
					block_size, ofs, filename);

		ofs += block_size;
	}
	msg ("close \"%s\"", filename);
	close (fd);
	msg ("total cycle to write sequntial : %lld", get_cycles()-start_cycles);
	check_file (filename, buf, buf_size);

}
void test_main(void)
{
	char filename[128];
	strlcpy(filename, "testfile", 9);
	/*
		 for(i = 0; i < num_of_child; i++)
		 {
		 filename[8] = i + '0';
		filename[9] = '\0';
		//Make childs to check	
	}
	*/
	test_write(filename);
}
